﻿using System.Windows.Media;

namespace MSHelpMe
{
    using System.IO;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using Hawaii.Services.Client;
    using Hawaii.Services.Client.Ocr;
    using Microsoft.Devices;
    using ViewModels;
    using System;

    public partial class PhotoCapture
    {
        public PhotoCamera Cam { get; set; }

        private PhotoCaptureState currentState;

        public PhotoCapture()
        {
            InitializeComponent();
        }

        public void ChangeState(PhotoCaptureState state)
        {
            this.currentState = state;
            this.currentState.ShowHideControls();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (Camera.IsCameraTypeSupported(CameraType.Primary))
            {
                this.ChangeState(new CapturingState(this));
                this.Cam = new PhotoCamera(CameraType.Primary);

                this.Cam.Initialized +=
                    (sender, arg) =>
                    {
                        // Set resolution to lower
                        this.Cam.Resolution = this.Cam.AvailableResolutions
                            .Where(r => (int)r.Width == 640 && (int)r.Height == 480)
                            .DefaultIfEmpty(this.Cam.AvailableResolutions.First())
                            .First();

                        this.Cam.FlashMode = FlashMode.Off;
                        this.currentState.FocusClick();
                    };

                this.Cam.CaptureImageAvailable +=
                    (sender, arg) =>
                    {

                        this.ChangeState(new ScanningState(this));

                        this.Dispatcher.BeginInvoke(
                            () =>
                            {
                                var img = new BitmapImage();
                                img.SetSource(arg.ImageStream);
                                imgPreview.Source = img;

                                this.Ocr(arg.ImageStream);
                            });
                    };

                Cam.AutoFocusCompleted +=
                    (sender, arg) => this.Dispatcher.BeginInvoke(
                        () =>
                        {
                            focusBrackets.Visibility = Visibility.Collapsed;
                        });

                viewfinderBrush.SetSource(this.Cam);

                CameraButtons.ShutterKeyHalfPressed += CameraButtons_ShutterKeyHalfPressed;
                CameraButtons.ShutterKeyPressed += CameraButtons_ShutterKeyPressed;
            }
            else
            {
                this.ChangeState(new ErrorState(this));

                this.Dispatcher.BeginInvoke(
                    () =>
                    {
                        txtError.Text = "Camera is not available.";
                    });
            }

            base.OnNavigatedTo(e);
        }

        protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            if (this.Cam != null)
            {
                this.Cam.Dispose();

                CameraButtons.ShutterKeyHalfPressed -= CameraButtons_ShutterKeyHalfPressed;
                CameraButtons.ShutterKeyPressed -= CameraButtons_ShutterKeyPressed;
            }

            base.OnNavigatingFrom(e);
        }

        private void Ocr(Stream img)
        {
            OcrService.RecognizeImageAsync(
                "[Hawaii ID]",
                GetPhotoBits(img),
                result =>
                {
                    this.Dispatcher.BeginInvoke(
                        () =>
                        {
                            scanProgress.Visibility = Visibility.Collapsed;
                            scanProgress.IsIndeterminate = false;
                        });

                    if (result.Status == Status.Success && result.OcrResult.OcrTexts.Count > 0)
                    {

                        this.Dispatcher.BeginInvoke(
                            () =>
                            {
                                btnAccept.Visibility = Visibility.Visible;
                            });

                        foreach (var i in result.OcrResult.OcrTexts.Where(i => !string.IsNullOrWhiteSpace(i.Text)))
                        {
                            // Show recognized words
                            var ocrtext = i;
                            this.Dispatcher.BeginInvoke(
                                () =>
                                {
                                    foreach (var w in ocrtext.Words)
                                    {
                                        var word = new TextBlock { Text = w.Text };
                                        var box = w.Box.Split(',');

                                        switch (ocrtext.Orientation.ToLowerInvariant())
                                        {
                                            case "up":
                                            case "down":
                                                word.SetValue(Canvas.LeftProperty, double.Parse(box[0]));
                                                word.SetValue(Canvas.TopProperty, double.Parse(box[1]));
                                                word.FontSize = Math.Max(16, Math.Min(60, double.Parse(box[3]) - 5));
                                                break;

                                            case "left":
                                            case "right":
                                                word.SetValue(Canvas.LeftProperty, double.Parse(box[0]));
                                                word.SetValue(Canvas.TopProperty, double.Parse(box[1]) + double.Parse(box[3]));
                                                word.FontSize = Math.Max(16, Math.Min(60, double.Parse(box[2]) - 5));
                                                word.RenderTransform = new RotateTransform
                                                                           {
                                                                               CenterX = 0,
                                                                               CenterY = 0,
                                                                               Angle = -90
                                                                           };
                                                break;
                                        }

                                        word.Tap += (sender, arg) =>
                                                         {
                                                             var self = sender as TextBlock;

                                                             if (self != null)
                                                             {
                                                                 words.Children.Remove(self);
                                                             }
                                                         };

                                        words.Children.Add(word);
                                    }
                                });
                        }


                        this.Dispatcher.BeginInvoke(
                            () =>
                            {
                                if (words.Children.Count == 0)
                                {
                                    txtError.Text = "No text Recognized.";
                                    txtError.Visibility = Visibility.Visible;
                                    btnAccept.Visibility = Visibility.Collapsed;
                                }
                            });

                    }
                    else
                    {
                        this.ChangeState(new ErrorState(this));

                        this.Dispatcher.BeginInvoke(
                            () =>
                            {
                                txtError.Text = result.Exception != null ? result.Exception.Message : "Scanning Failed.";
                            });
                    }
                });
        }

        /// <summary>
        /// Returns a byte array with the content of the stream.
        /// </summary>
        private static byte[] GetPhotoBits(Stream stream)
        {
            var photoBits = new byte[stream.Length];

            stream.Seek(0, SeekOrigin.Begin);
            stream.Read(photoBits, 0, photoBits.Length);
            stream.Close();

            return photoBits;
        }

        private void viewfinder_Tap(object sender, GestureEventArgs e)
        {
            this.currentState.FocusClick();
        }

        private void btnShutter_Click(object sender, RoutedEventArgs e)
        {
            this.currentState.ShutterClick();
        }

        private void btnAccept_Click(object sender, RoutedEventArgs e)
        {
            if (!this.currentState.AcceptClick())
            {
                return;
            }

            if (NavigationService.CanGoBack)
            {
                NavigationService.GoBack();
            }
        }

        private void btnCapture_Click(object sender, RoutedEventArgs e)
        {
            this.currentState.RecaptureClick();
        }

        void CameraButtons_ShutterKeyPressed(object sender, EventArgs e)
        {
            this.currentState.ShutterClick();
        }

        void CameraButtons_ShutterKeyHalfPressed(object sender, EventArgs e)
        {
            this.currentState.FocusClick();
        }
    }
}